#ifndef __SINGLETON_H_
#define __SINGLETON_H_


#include "base/nocopyable.h"
#include <assert.h>
#include <pthread.h>
#include <stdlib.h> // atexit

namespace tb
{
namespace detail
{
    template<typename T>
    struct has_no_destory
    {
        template <typename C> static char test(decltype(&C::nodestory));
        template <typename C> static int32_t test(...);
        const static bool value = sizeof(test<T>(0)) == 1;
    };
}   // namespace detail

template <typename T>
class Singleton : public nocopyable
{
public:
    Singleton() = delete;
    ~Singleton() = delete;

    static T& instance()
    {
        pthread_once(&ponce_, &Singleton::init);
        assert(value_ != NULL);
        return *value_;
    }
private:
    static void init()
    {
        value_ = new T();
        if (!detail::has_no_destroy<T>::value)
        {
        ::atexit(destroy);
        }
    }

    static destory()
    {
        typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
        T_must_be_complete_type dummy; (void) dummy;

        delete value_;
        value_ = NULL;
    }
private:
    static pthread_once_t ponce_;
    static T*             value_;
};

template <typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;

template <typename T>
T* Singleton<T>::value_ = NULL;

}   // namespace tb

#endif  // __SINGLETON_H_
